package co.yixiang.yshop.module.crm.service.crmanalysis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import co.yixiang.yshop.framework.common.enums.CommonStatusEnum;
import co.yixiang.yshop.framework.common.enums.ShopCommonEnum;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.framework.common.util.collection.CollectionUtils;
import co.yixiang.yshop.framework.common.util.object.BeanUtils;
import co.yixiang.yshop.framework.mybatis.core.query.LambdaQueryWrapperX;
import co.yixiang.yshop.framework.security.core.util.SecurityFrameworkUtils;
import co.yixiang.yshop.module.crm.controller.admin.crmachievement.vo.CrmAchievementRespVO;
import co.yixiang.yshop.module.crm.controller.admin.crmachievement.vo.DeptAchieveRespVO;
import co.yixiang.yshop.module.crm.controller.admin.crmachievement.vo.UserAchieveRespVO;
import co.yixiang.yshop.module.crm.controller.admin.crmanalysis.vo.*;
import co.yixiang.yshop.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmclues.CrmCluesDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmcontract.CrmContractDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
import co.yixiang.yshop.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import co.yixiang.yshop.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
import co.yixiang.yshop.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
import co.yixiang.yshop.module.crm.dal.mysql.crmclues.CrmCluesMapper;
import co.yixiang.yshop.module.crm.dal.mysql.crmcontract.CrmContractMapper;
import co.yixiang.yshop.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
import co.yixiang.yshop.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
import co.yixiang.yshop.module.crm.enums.CluesStatusEnum;
import co.yixiang.yshop.module.crm.enums.ContractStatusEnum;
import co.yixiang.yshop.module.crm.enums.FlowStepEnum;
import co.yixiang.yshop.module.crm.enums.RelationEnum;
import co.yixiang.yshop.module.system.api.user.AdminUserApi;
import co.yixiang.yshop.module.system.api.user.dto.AdminUserRespDTO;
import co.yixiang.yshop.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import co.yixiang.yshop.module.system.controller.admin.user.vo.user.UserPageReqVO;
import co.yixiang.yshop.module.system.dal.dataobject.dept.DeptDO;
import co.yixiang.yshop.module.system.dal.dataobject.user.AdminUserDO;
import co.yixiang.yshop.module.system.dal.mysql.user.AdminUserMapper;
import co.yixiang.yshop.module.system.service.dept.DeptService;
import co.yixiang.yshop.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import kotlin.internal.ContractsDsl;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 业绩目标 Service 实现类
 *
 * @author yshop
 */
@Service
@Validated
public class AchievementServiceImpl implements AchievementService {

    @Resource
    private CrmAchievementMapper achievementMapper;
    @Resource
    private DeptService deptService;
    @Resource
    private AdminUserService userService;
    @Resource
    private CrmContractMapper contractMapper;
    @Resource
    private CrmContractReceivablesMapper contractReceivablesMapper;
    @Resource
    private CrmCustomerMapper customerMapper;
    @Resource
    private CrmBusinessMapper businessMapper;
    @Resource
    private CrmCluesMapper crmCluesMapper;
    @Resource
    private AdminUserApi adminUserApi;





    @Override
    public PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO) {
        UserPageReqVO userPageReqVO = new UserPageReqVO();
        userPageReqVO.setPageNo(pageReqVO.getPageNo());
        userPageReqVO.setPageSize(pageReqVO.getPageSize());
        userPageReqVO.setUsername(pageReqVO.getName());
        PageResult<AdminUserDO> pageResult = userService.getUserPage(userPageReqVO);
        PageResult<UserAchieveVO> pageResult1 = BeanUtils.toBean(pageResult,UserAchieveVO.class);
        pageResult1.getList().forEach(v -> {
            LambdaQueryWrapperX<CrmContractDO> wrapperX = new LambdaQueryWrapperX<>();
            wrapperX.eq(CrmContractDO::getOwnerUserId,v.getId())
                    .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
                    .betweenIfPresent(CrmContractDO::getCreateTime,pageReqVO.getCreateTime());
            v.setContractCount(contractMapper.selectCount(wrapperX));
            List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapperX);
            BigDecimal contractMoney = crmContractDOS
                    .stream()
                    .map(CrmContractDO::getMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            v.setContractMoney(contractMoney);
            List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
                    .selectList(new LambdaQueryWrapperX<CrmContractReceivablesDO>()
                            .eq(CrmContractReceivablesDO::getOwnerUserId,v.getId())
                            .eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
                            .betweenIfPresent(CrmContractReceivablesDO::getCreateTime,pageReqVO.getCreateTime()));
            BigDecimal receivablesMoney = crmContractReceivablesDOS
                    .stream()
                    .map(CrmContractReceivablesDO::getMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            v.setReceivablesMoney(receivablesMoney);

            LambdaQueryWrapperX<CrmCluesDO> wrapperX2 = new LambdaQueryWrapperX<>();
            wrapperX2.eq(CrmCluesDO::getOwnerUserId,v.getId())
                    .betweenIfPresent(CrmCluesDO::getCreateTime,pageReqVO.getCreateTime());
            Long cluesCount = crmCluesMapper.selectCount(wrapperX2);
            v.setCluesCount(cluesCount);

            wrapperX2.eq(CrmCluesDO::getStatus, CluesStatusEnum.STATUS_1.getValue());
            Long cluesToCustomerCount = crmCluesMapper.selectCount(wrapperX2);
            v.setCluesToCustomerCount(cluesToCustomerCount);
            String per = "0";
            if(cluesCount > 0){
                per = NumberUtil.round(NumberUtil.div(cluesToCustomerCount,cluesCount),2)
                        .multiply(new BigDecimal("100")).toString();
            }
            v.setCluesToCustomerPer(per);

        });

        return pageResult1;
    }

    @Override
    public List<DeptAchieveVO> getDeptAchieve(AchievementPageReqVO pageReqVO) {
        List<DeptDO> list = deptService.getDeptList(
                new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
        List<DeptAchieveVO> achieveRespVOS = BeanUtils.toBean(list,DeptAchieveVO.class);
        achieveRespVOS.forEach(vo -> {
            List<AdminUserRespDTO> adminUserRespDTOS = adminUserApi.getUserListByDeptIds(CollUtil.newArrayList(vo.getId()));
            List<Long> ids = CollUtil.newArrayList(-1L);
            if(!adminUserRespDTOS.isEmpty()){
                ids = adminUserRespDTOS.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
            }
            LambdaQueryWrapperX<CrmContractDO> wrapperX = new LambdaQueryWrapperX<>();
            wrapperX.inIfPresent(CrmContractDO::getOwnerUserId,ids)
                    .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
                    .betweenIfPresent(CrmContractDO::getCreateTime,pageReqVO.getCreateTime());
            List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapperX);
            BigDecimal contractMoney = crmContractDOS
                    .stream()
                    .map(CrmContractDO::getMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal receivablesMoney = crmContractDOS
                    .stream()
                    .map(CrmContractDO::getReturnMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            vo.setContractCount(Long.valueOf(crmContractDOS.size()));
            vo.setContractMoney(contractMoney);
            vo.setReceivablesMoney(receivablesMoney);
        });
        return achieveRespVOS;
    }


    @Override
    public List<CompletionVO> getCompletion(String relation) {
        Integer year = DateUtil.year(new Date());
        List<Long> userIds = new ArrayList<>();
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if(RelationEnum.MY.getValue().equals(relation)){
            userIds.add(userId);
        }else if(RelationEnum.SUB.getValue().equals(relation)){
            userIds = adminUserApi.getUserListBySubordinateIds(userId);
        }
        //合同目标
        List<CrmAchievementDO> crmAchievementDO = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
                .eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
                .in(CrmAchievementDO::getTypeId,userIds)
                .eqIfPresent(CrmAchievementDO::getConfig, ShopCommonEnum.ACH_1.getValue())
                .eqIfPresent(CrmAchievementDO::getYear,year));

        List<CompletionVO> completionVOS = new ArrayList<>();
        int i = 1;
        while (i <= 12) {
            BigDecimal targetPrice = BigDecimal.ZERO;
            BigDecimal successPrice = BigDecimal.ZERO;
            Long successCount = 0L;
            BigDecimal perPrice = BigDecimal.ZERO;
            String time = "" + year;
            if(i < 10) {
                time = time + "-0" + i;
            }else{
                time = time + "-" + i;
            }
            CompletionVO completionVO = new CompletionVO();
            completionVO.setTime(time);
            switch (i) {
                case 1 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getJanuary)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 2 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getFebruary)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 3 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getMarch)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 4 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getApril)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 5 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getMay)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 6 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getJune)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 7 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getJuly)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 8 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getAugust)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 9 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getSeptember)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 10 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getOctober)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 11 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getNovember)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 12 -> {
                    if(crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getDecember)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
            }

            Date starTime = new Date();
            Date endTime = new Date();
            Calendar calendar = Calendar.getInstance();
            //某个月
            calendar.set(year,i - 1,1);
            starTime = DateUtil.beginOfMonth(calendar.getTime());
            endTime = DateUtil.endOfMonth(calendar.getTime());

            LambdaQueryWrapper<CrmContractDO> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(CrmContractDO::getOwnerUserId,userIds)
                    .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
                    .between(CrmContractDO::getOrderTime,starTime,endTime);
            List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapper);

            if(!crmContractDOS.isEmpty()){
                successPrice = crmContractDOS
                        .stream()
                        .map(CrmContractDO::getMoney)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                successCount = Long.valueOf(crmContractDOS.size());

                if(successCount > 0){
                    perPrice = NumberUtil.round(NumberUtil.div(successPrice,successCount),2);
                }
            }
            completionVO.setSuccessPrice(successPrice);
            completionVO.setSuccessCount(successCount);
            completionVO.setTargetPrice(targetPrice);
            completionVO.setPerPrice(perPrice);
            completionVOS.add(completionVO);
            i++;
        }
        return completionVOS;
    }

    @Override
    public List<SalesVO> getSales(String relation) {
        Integer year = DateUtil.year(new Date());
        List<Long> userIds = new ArrayList<>();
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if(RelationEnum.MY.getValue().equals(relation)){
            userIds.add(userId);
        }else if(RelationEnum.SUB.getValue().equals(relation)){
            userIds = adminUserApi.getUserListBySubordinateIds(userId);
        }
        List<SalesVO> salesVOS = new ArrayList<>();
        int i = 1;
        while (i <= 12) {
            String time = "" + year;
            if(i < 10) {
                time = time + "-0" + i;
            }else{
                time = time + "-" + i;
            }
            SalesVO salesVO = new SalesVO();
            salesVO.setTime(time);

            Date starTime = new Date();
            Date endTime = new Date();
            Calendar calendar = Calendar.getInstance();
            //某个月
            calendar.set(year,i - 1,1);
            starTime = DateUtil.beginOfMonth(calendar.getTime());
            endTime = DateUtil.endOfMonth(calendar.getTime());

            Long cluesCount = crmCluesMapper.selectCount( new LambdaQueryWrapper<CrmCluesDO>()
                    .in(CrmCluesDO::getOwnerUserId,userIds)
                    .between(CrmCluesDO::getCreateTime,starTime,endTime));
            Long customerCount = customerMapper.selectCount( new LambdaQueryWrapper<CrmCustomerDO>()
                    .in(CrmCustomerDO::getOwnerUserId,userIds)
                    .between(CrmCustomerDO::getCreateTime,starTime,endTime));
            Long businessCount = businessMapper.selectCount( new LambdaQueryWrapper<CrmBusinessDO>()
                    .in(CrmBusinessDO::getOwnerUserId,userIds)
                    .between(CrmBusinessDO::getCreateTime,starTime,endTime));
            Long contractCount = contractMapper.selectCount( new LambdaQueryWrapper<CrmContractDO>()
                    .in(CrmContractDO::getOwnerUserId,userIds)
                    .between(CrmContractDO::getOrderTime,starTime,endTime));
            Long receivablesCount = contractReceivablesMapper.selectCount( new LambdaQueryWrapper<CrmContractReceivablesDO>()
                    .in(CrmContractReceivablesDO::getOwnerUserId,userIds)
                    .between(CrmContractReceivablesDO::getReturnTime,starTime,endTime));
            salesVO.setCluesCount(contractCount);
            salesVO.setCustomerCount(customerCount);
            salesVO.setBusinessCount(businessCount);
            salesVO.setContractCount(contractCount);
            salesVO.setReceivablesCount(receivablesCount);
            salesVOS.add(salesVO);
            i++;
        }
        return salesVOS;
    }
}